package rbac

import (
	"context"
	"gitee.com/bobo-rs/idea-space-framework/enums"
	"gitee.com/bobo-rs/idea-space-framework/framework/dao"
	"gitee.com/bobo-rs/idea-space-framework/framework/model"
	"gitee.com/bobo-rs/idea-space-framework/framework/model/entity"
	"gitee.com/bobo-rs/idea-space-framework/pkg/algorithm/treenode"
	"gitee.com/bobo-rs/idea-space-framework/pkg/exception"
	"gitee.com/bobo-rs/idea-space-framework/pkg/utils"
	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/frame/g"
)

const (
	// permissionsDefaultSort 权限排序：菜单类型>排序值>是否禁用
	permissionsDefaultSort = `menu_type asc, sort asc, is_disabled asc`
)

// SavePermissions 保存权限
func (r *sRbac) SavePermissions(ctx context.Context, pm entity.Permissions) error {
	// 保存菜单数据
	res, err := dao.Permissions.Ctx(ctx).OmitEmpty().Save(pm)
	if err != nil {
		return exception.New(`保存权限失败,请重试`)
	}
	// 获取权限ID
	pmId, err := res.LastInsertId()
	if err != nil {
		return exception.New(`保存权限失败`)
	}
	// 是否禁用
	if enums.PermDisabled(pm.IsDisabled) == enums.PermDisabledLock {
		_ = r.RemovePermAssocByPmId(ctx, uint(pmId))
	}
	return nil
}

// GetPermTreeList 获取权限树形列表
func (r *sRbac) GetPermTreeList(ctx context.Context) ([]map[string]interface{}, error) {
	var (
		rows        = make([]model.PermissionsListItem, 0)
		treeHandler = treenode.New()
	)
	// 获取权限列表
	err := dao.Permissions.Ctx(ctx).
		Order(permissionsDefaultSort).
		Scan(&rows)
	if err != nil {
		return nil, exception.New(`暂无数据`)
	}

	// 构建树形结构
	treeList, err := treeHandler.BuildTree(rows)
	if err != nil {
		return nil, exception.New(err.Error())
	}
	return treeList, nil
}

// GetPermDetail 获取权限详情
func (r *sRbac) GetPermDetail(ctx context.Context, permId uint) (*entity.Permissions, error) {
	var (
		detail *entity.Permissions
	)
	err := r.PermissionsModel().Scan(ctx, g.Map{
		dao.Permissions.Columns().Id: permId,
	}, &detail)
	return detail, err
}

// GetPermMenuTreeList 菜单列表-获取权限菜单树形列表
func (r *sRbac) GetPermMenuTreeList(ctx context.Context, id ...uint) ([]map[string]interface{}, error) {
	var (
		rows        []model.PermissionsTreeItem
		treeHandler = treenode.New()
		where       = g.Map{
			dao.Permissions.Columns().MenuType: []enums.PermMenuType{
				enums.PermMenuTypeMain, enums.PermMenuTypeSub,
			},
			dao.Permissions.Columns().IsDisabled: enums.PermDisabledOk,
		}
	)
	if len(id) > 0 {
		where[dao.Permissions.Columns().Id] = id
	}

	// 获取权限列表
	err := r.PermissionsModel().Scan(ctx, where, &rows)
	if err != nil {
		return nil, exception.New(`暂无数据`)
	}

	// 构建树形结构
	treeList, err := treeHandler.BuildTree(rows)
	if err != nil {
		return nil, exception.New(err.Error())
	}
	return treeList, nil
}

// GetPermAssocTreeListByAssocId 通过关联ID-获取关联权限树形列表（角色关联、管理员关联）
func (r *sRbac) GetPermAssocTreeListByAssocId(ctx context.Context, assocType enums.PermAssocType, assocId uint) ([]map[string]interface{}, error) {
	// 获取权限ID
	findId, _ := r.GetPermissionsIdByAssocId(ctx, assocType, assocId)

	// 获取权限
	return r.GetPermAssocTreeList(ctx, false, findId...)
}

// GetPermAssocTreeList 获取权限关联树形列表-true关联子级菜单类型，false权限关联角色
func (r *sRbac) GetPermAssocTreeList(ctx context.Context, assocTreeType bool, findId ...uint) ([]map[string]interface{}, error) {
	var (
		rows  []model.PermissionsTreeItem
		where = g.Map{
			dao.Permissions.Columns().IsDisabled: enums.PermDisabledOk,
		}
	)

	// 子级权限关联父级菜单类型
	if assocTreeType == true {
		where[dao.Permissions.Columns().MenuType] = []enums.PermMenuType{
			enums.PermMenuTypeMain, enums.PermMenuTypeSub,
		}
	}

	// 获取权限列表
	err := r.PermissionsModel().Scan(ctx, where, &rows)
	if err != nil {
		return nil, exception.New(`暂无数据`)
	}

	// 构建树形结构
	return treenode.New().BuildFindTreeNode(rows, findId)
}

// GetMenuActionCode 通过权限ID获取权限码
func (r *sRbac) GetMenuActionCode(ctx context.Context, id ...uint) (out *model.PermCodeActionItem, err error) {
	var (
		where = g.Map{
			dao.Permissions.Columns().IsDisabled: enums.PermDisabledOk,
		}
		rows []model.PermissionsPathCodeItem
	)
	if len(id) > 0 {
		where[dao.Permissions.Columns().Id] = id
	}

	// 获取权限列表
	err = r.PermissionsModel().Scan(ctx, where, &rows)
	if err != nil {
		return nil, err
	}
	if len(rows) == 0 {
		return nil, exception.New(`权限不存在`)
	}

	// 处理菜单权限码
	return r.processMenuActionCode(rows), nil
}

// PermCustomUpdateColumns 自定义字段更新权限字段
func (r *sRbac) PermCustomUpdateColumns(ctx context.Context, in model.PermCustomUpdateColumnInput) error {
	// 更新数据
	return r.PermissionsModel().UpdatePri(ctx, in.PermId, in.Columns.Fmt(), in.Value)
}

// RemovePermissions 删除权限数据
func (r *sRbac) RemovePermissions(ctx context.Context, id uint) error {
	// 是否存在子权限
	if r.CheckPermissionsExistsByPid(ctx, id) {
		return exception.New(`请移动子级权限才能删除`)
	}

	// 删除权限
	return dao.Permissions.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
		_, err := tx.Ctx(ctx).Delete(dao.Permissions.Table(), g.Map{
			dao.Permissions.Columns().Id: id,
		})
		if err != nil {
			return exception.New(`权限删除失败，请重试`)
		}
		return r.RemovePermAssocByPmId(ctx, id)
	})
}

// processMenuActionCode 处理菜单权限码
func (r *sRbac) processMenuActionCode(rows []model.PermissionsPathCodeItem) (out *model.PermCodeActionItem) {
	if len(rows) == 0 {
		return nil
	}
	var (
		viewPaths   = make([]model.PermissionsPathCodeItem, 0) // 页面地址
		permCodeMap = make(map[uint]map[string]string)         // 权限码字典
	)

	// 迭代处理菜单权限操作码
	out = &model.PermCodeActionItem{
		ActionCode: make(map[string]map[string]string),
		ActionApi:  make(map[string]string),
	}
	for _, item := range rows {
		// 接口地址
		if item.ApiPath != "" {
			out.ActionApi[utils.Slugify(item.ApiPath)] = item.Name
		}
		// 是否页面地址
		if item.Path != "" {
			viewPaths = append(viewPaths, item)
		}
		// 权限码
		if item.PermCode != "" {
			codeMap, ok := permCodeMap[item.Pid]
			if !ok {
				codeMap = make(map[string]string)
			}
			codeMap[item.PermCode] = item.Name
			// 赋值
			permCodeMap[item.Pid] = codeMap
		}
	}

	// 组合页面地址和权限码
	for _, item := range viewPaths {
		codeMap, ok := permCodeMap[item.Id]
		if !ok {
			codeMap = make(map[string]string)
		}
		out.ActionCode[utils.Slugify(item.Path)] = codeMap
	}
	return out
}
